
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;
import java.util.ArrayList;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;

/**
 * A program that analyzes the frequency of letter-combinations in an input file. The ten most
 * frequent letter combinations are printed to the console.
 * 
 * @author brad
 * 
 */

public class SimpleAnalysis extends JFrame {
	// Important GUI controls
	private JTextField textWindowSize = new JTextField("1");
	private JTextField textFileName = new JTextField("");
	private JButton btnFileBrowser = new JButton("Browse");
	private JButton btnAnalyze = new JButton("Start analysis");
	private Window2 w2 = new Window2();
	
	// File browser for later use
	private final JFileChooser fileChooser = new JFileChooser();

	public static void main(String[] args) {
		new SimpleAnalysis();
	}

	private SimpleAnalysis() {
		// General application settings
		this.setTitle("Letter frequency Analysis");
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);

		// Set up GUI and the event handling
		createGUI();
		addEventHandlers();

		// All done, show the application
		this.pack();
		this.setVisible(true);
	}

	private void createGUI() {
		// Set the layout manager, and a common border to use
		Container content = this.getContentPane();
		content.setLayout(new GridLayout(3, 1));
		Border whiteSpaceBorder = new EmptyBorder(5, 5, 5, 5);

		// Top box with window-size
		Box topBox = Box.createHorizontalBox();
		content.add(topBox);
		topBox.setBorder(whiteSpaceBorder);
		topBox.add(new JLabel("Window size"));
		topBox.add(Box.createHorizontalStrut(5));
		textWindowSize.setPreferredSize(new Dimension(50, 0));
		textWindowSize.setMaximumSize(new Dimension(50, 50));
		textWindowSize.setHorizontalAlignment(JTextField.CENTER);
		topBox.add(textWindowSize);
		topBox.add(Box.createHorizontalGlue());

		// Center box with file-name and file browser
		Box centerBox = Box.createHorizontalBox();
		content.add(centerBox);
		centerBox.setBorder(whiteSpaceBorder);
		centerBox.add(new JLabel("Input file"));
		centerBox.add(Box.createHorizontalStrut(5));
		textFileName.setPreferredSize(new Dimension(250, 0));
		centerBox.add(textFileName);
		centerBox.add(Box.createHorizontalStrut(5));
		centerBox.add(btnFileBrowser);

		// Bottom box - the "analyze" button
		Box bottomBox = Box.createHorizontalBox();
		content.add(bottomBox);
		bottomBox.setBorder(whiteSpaceBorder);
		bottomBox.add(Box.createHorizontalGlue());
		bottomBox.add(btnAnalyze);
	}

	private void addEventHandlers() {
		// The file-browser
		btnFileBrowser.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent evt) {
				chooseInputFile();
			}
		});

		// The analysis
		btnAnalyze.addMouseListener(new MouseAdapter() {
			public void mouseClicked(MouseEvent evt) {
				analyze();
				secondWindow();
			}
		});
	}
	
	/**
	 * Display a JFileChooser, and copy the name of the selected file into
	 * the text-field for display to the user
	 */
	private void chooseInputFile() {
		int result = fileChooser.showOpenDialog(this);

    if (result == JFileChooser.APPROVE_OPTION) {
        File file = fileChooser.getSelectedFile();
        textFileName.setText(file.getAbsolutePath());
    }	}

	/**
	 * The analyse method checks the input file for validity, and the creates a separate "Analyzer"
	 * object to carry out the analysis.
	 * 
	 * Note: having a separate class for the analysis is not necessary for this simple example.
	 * However, it shows the idea of separating major functions into separate classes. In this case,
	 * we are separating the GUI functions from the analysis functions.
	 * 
	 * @return no return value
	 */
	private void analyze() {
		// Do we have a valid input file? If so, checkInputFile returns
		// a valid file-object. Otherwise it returns null.
		String fileName = textFileName.getText();
		File inputFile = checkInputFile(fileName);
		
		// Do we have a valid window size?
		int windowSize = checkWindowSize(textWindowSize.getText());
		
		// If the input file is valid (i.e., we have a valid File object)
		// then carry out the analysis.
		if (inputFile != null & windowSize > 0) {
			SimpleAnalyzer analyzer = new SimpleAnalyzer(inputFile, windowSize);
			try {
				analyzer.analyze();
			} catch (IOException e) {
				JOptionPane.showMessageDialog(this, e.toString(), "Error during analysis", JOptionPane.ERROR_MESSAGE);
			}
			analyzer.printResults();
			generate(analyzer);
		}
		
	}
	
	/**
	 * The secondWindow method is setting the second GUI to visible. And prints the read text into the right column.
	 */
	private void secondWindow(){
		
		String fileName = textFileName.getText();
		
		try{
			BufferedReader in = new BufferedReader (new FileReader(fileName));
			String line;
			while((line = in.readLine()) != null){
				w2.setInputText(line);
			}
		in.close();
		} catch (Exception e) {
			e.toString();
		}

		w2.setVisible(true);
	}
	
	/**
	 * Check the input file for validity: it must exist, be a file, and be readable.
	 * In case of an error, display an error dialog.
	 * 
	 * @param fileName The name of the file to check
	 * 
	 * @return no return value
	 */
	private File checkInputFile(String fileName) {
		boolean allOk = false;
		File fileIn = new File(fileName);
		
		if (!fileIn.exists()) {
			JOptionPane.showMessageDialog(this, "File does not exist", "File error", JOptionPane.ERROR_MESSAGE);
		} else if (!fileIn.isFile()) {
			JOptionPane.showMessageDialog(this, "Must be a file, not a directory", "File error", JOptionPane.ERROR_MESSAGE);
		} else if (!fileIn.canRead()) {
			JOptionPane.showMessageDialog(this, "File is not readable", "File error", JOptionPane.ERROR_MESSAGE);
		} else {
			allOk = true;
		}
		
		if (!allOk) fileIn = null;
		
		return fileIn;
	}
	
	/** Check the window size for validity: we accept values from 1 through 7.
	 * In case of an error, we return -1
	 * 
	 * @param windowSize as a string
	 * 
	 * @return windowSize as an int
	 */
	private int checkWindowSize(String textSize) {
		int outputSize = -1;
		
		try {
			int tmpSize = Integer.parseInt(textSize);
			if (tmpSize >= 1 & tmpSize <= 7) {
				outputSize = tmpSize;
			}
		} catch (Exception e) {
			// Do nothing; output size already set to invalid value
		}
	  return outputSize;
	}
	/**
	 * This method coordinates the text generation in interaction with class Simple Analyzer
	 * @param analyzer is an Object of the class SimpleAnalyzer
	 */
	public void generate(SimpleAnalyzer analyzer){

		char [] cache = new char [checkWindowSize(textWindowSize.getText())-1];
		ArrayList <Character> generated = new ArrayList <Character>();
		
		for (int i = 0; i < cache.length; i++){
			if(i != (cache.length-1)){
				cache [i] =' ';
			} else {
				cache [i] = analyzer.getFirstLetter();
				generated.add(cache[i]);
			}
		}
		
		int textLength = (int) (Math.random()*10000);
		for(int i = 0; i < textLength; i++){
			char gen = analyzer.generateText(cache);
			if(cache[cache.length-1] == ' ' && gen == ' ');
			else{
				generated.add(gen);
				for(int y = 0; y < cache.length; y++){
					if(y != (cache.length-1)){
						cache[y] = cache[y+1];
					}else{
						cache[y] = gen;
					}
				}
			}
		}
		for(int i = 0; i < generated.size(); i++){
			textOutput(generated.get(i));
		}
	}
	
	/**
	 * This method overhands a char to the Window2 to print it in the text printout area
	 */
	public void textOutput (char x){
		w2.setOutputText(x);
	}
}
